/*
    This file is part of libtiming.

    libtiming is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    libtiming is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with libtiming.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "timeout.h"

#include <QtGlobal>

#if defined(Q_WS_X11)
	
	#include <time.h>
	#include <sys/time.h>
	#include <sys/timex.h>
	#include <sys/types.h>
	
#elif defined(Q_WS_WIN)
	
	
	
#elif defined(Q_WS_MAC)
	
	
	
#else
	
	#error Unsupported platform.
	
#endif

using namespace Timing;



class PlatformDependantTimeValue
{

private:
	
#if defined(Q_WS_X11)
	
	struct ntptimeval _value;
	
#elif defined(Q_WS_WIN)
#elif defined(Q_WS_MAC)
#endif

	PlatformDependantTimeValue(const PlatformDependantTimeValue & other);
	
	PlatformDependantTimeValue & operator= (const PlatformDependantTimeValue & rhs);
	
public:
	
	~PlatformDependantTimeValue()
	{
	#if defined(Q_WS_X11)
	#elif defined(Q_WS_WIN)
	#elif defined(Q_WS_MAC)
	#endif
	}
	
	PlatformDependantTimeValue()
	#if defined(Q_WS_X11)
		
		: _value()
		
	#elif defined(Q_WS_WIN)
	#elif defined(Q_WS_MAC)
	#endif
	{
	#if defined(Q_WS_X11)
	#elif defined(Q_WS_WIN)
	#elif defined(Q_WS_MAC)
	#endif
		
		now();
	}
	
	bool operator< (const PlatformDependantTimeValue & rhs)
	{
	#if defined(Q_WS_X11)
		
		bool result = false;
		
		if(_value.time.tv_sec < rhs._value.time.tv_sec)
		{
			result = true;
		}
		else if(_value.time.tv_sec == rhs._value.time.tv_sec)
		{
			result = (_value.time.tv_usec < rhs._value.time.tv_usec);
		}
		
		return result;
		
	#elif defined(Q_WS_WIN)
	#elif defined(Q_WS_MAC)
	#endif
	}
	
	void now()
	{
	#if defined(Q_WS_X11)
		
		ntp_gettime(&_value);
		
	#elif defined(Q_WS_WIN)
	#elif defined(Q_WS_MAC)
	#endif
	}
	
	void nowPlus(float value)
	{
		now();
		
	#if defined(Q_WS_X11)
		
		const int64_t MICROSECONDS_IN_A_SECOND = 1000000;
		int64_t microseconds = value * MICROSECONDS_IN_A_SECOND;
		int64_t seconds = microseconds / MICROSECONDS_IN_A_SECOND;
		microseconds -= seconds * MICROSECONDS_IN_A_SECOND;
		
		_value.time.tv_sec += seconds;
		
		if(_value.time.tv_usec + microseconds > MICROSECONDS_IN_A_SECOND)
		{
			_value.time.tv_sec += 1;
			_value.time.tv_usec += microseconds - MICROSECONDS_IN_A_SECOND;
		}
		else
		{
			_value.time.tv_usec += microseconds;
		}
		
	#elif defined(Q_WS_WIN)
	#elif defined(Q_WS_MAC)
	#endif
	}
	
};

Timeout::~Timeout()
{
	/* does nothing */
}

Timeout::Timeout()
	: _timeValue(new PlatformDependantTimeValue())
{
	/* does nothing */
}

void Timeout::timeOutIn(float seconds)
{
	_timeValue->nowPlus(seconds);
}

bool Timeout::hasNotTimedOut() const
{
#if defined(Q_WS_X11)
	
	return PlatformDependantTimeValue() < *_timeValue;
	
#elif defined(Q_WS_WIN)
	
	return false;
	
#elif defined(Q_WS_MAC)
	
	return false;
	
#endif
}

void Timeout::sleep(float value)
{
#if defined(Q_WS_X11)
	
	const int64_t NANOSECONDS_IN_A_SECOND = 1000000000;
	int64_t nanoseconds = value * NANOSECONDS_IN_A_SECOND;
	int64_t seconds = nanoseconds / NANOSECONDS_IN_A_SECOND;
	nanoseconds -= seconds * NANOSECONDS_IN_A_SECOND;
	
	struct timespec sleepTime;
	sleepTime.tv_sec = seconds;
	sleepTime.tv_nsec = nanoseconds;
	
	nanosleep(&sleepTime, 0);
	
#elif defined(Q_WS_WIN)
#elif defined(Q_WS_MAC)
#endif
}
